<?php

/**
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 3 of the License.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 */

namespace Util;

/**
 * CSV handling 
 * @package Util
 * @author Somlyai Dezső
 * @author Vincze Tamas
 * @version 0.1
 */
class Csv {

	/**
	 * The csv parsed data.
	 * @access protected
	 * @var array
	 */
	protected $_data;

	/**
	 * CSV row separator.
	 * @access protected
	 * @var string
	 */
	protected $_separator;

	/**
	 * Use First Row of CSV as header.
	 * @access protected
	 * @var bool
	 */
	protected $_useHeader;

	/**
	 * CSV content file.
	 * @access protected
	 * @var string
	 */
	protected $_file;

	/**
	 * Constructor.
	 * @access private
	 * @param string|array $dataOrFile
	 * @param string $separator
	 * @param bool $header
	 * @return void
	 */
	private function __construct($dataOrFile, $header, $separator) {
		$this->_separator = $separator;
		$this->_useHeader = $header;
		if (is_array($dataOrFile)) {
			$this->_data = $dataOrFile;
		} else {
			$this->_file = $dataOrFile;
			$this->_data = $this->_readFile($dataOrFile);
		}
	}

	/**
	 * Factory method of CSVParser.
	 * @access public
	 * @access static
	 * @param string|array $dataOrFile
	 * @param bool $header
	 * @param string $separator
	 * @return Csv
	 */
	public static function init($dataOrFile, $header = true, $separator = ";") {
		return new self($dataOrFile, $header, $separator);
	}

	/**
	 * Read CSV and converting array.
	 * @access public
	 * @return array
	 */
	protected function _readFile($filePath) {
		$rows = explode(chr(13).chr(10), mb_convert_encoding(\Util\FileHandler::init($filePath)->getContents(), "UTF-8", "ISO-8859-2"));
		if ($this->_useHeader) {
			$header = array_shift($rows);
			$header = $this->_rowSplit($header);
		}

		$i = 0;
		$data = array();
		foreach ($rows as $row) {
			$csvRowElements = $this->_rowSplit($row);

			if (!Validate::isEmptyArray($csvRowElements)) {
				foreach ($csvRowElements as $key => $element) {
					if (isset($header)) {
						$data[$i][trim($header[$key])] = trim($element);
					} else {
						$data[$i][] = trim($element);
					}
				}
				$i++;
			}
		}
		return $data;
	}

	/**
	 * Spliting CSV row.
	 * @access protected
	 * @param string $row
	 * @return array
	 */
	protected function _rowSplit($row) {
		$expr = "/" . $this->_separator . "(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/";
		$results = preg_split($expr, trim($row));
		return preg_replace("/^\"(.*)\"$/", "$1", $results);
	}

	/**
	 * Save to file
	 * @access public
	 * @param string|null $filePath
	 */
	public function saveFile($filePath = null) {
		if (is_null($filePath) && is_null($this->_file)) {
			$filePath = DIR_WEBROOT .  "export-" . date("Ymd") . ".csv";
		}
		$this->_output("FILE", $filePath);
	}

	/**
	 * Force download file
	 * @access public
	 * @param type $fileName 
	 */
	public function forceDownload($fileName = null) {
		$this->_output("DOWNLOAD", $fileName);
	}

	/**
	 * Get content to string
	 * @access public
	 * @return string
	 */
	public function toString() {
		return $this->_output();
	}

	/**
	 * Get content to array
	 * @access public
	 * @return array
	 */
	public function toArray() {
		return $this->_data;
	}

	/**
	 * Gets the data by action
	 * @access protected
	 * @param string|null $action
	 * @param string|null $parameter
	 * @return string 
	 */
	protected function _output($action, $parameter = false) {
		$content = "";
		if ($this->_useHeader) {
			$content = join($this->_separator, array_keys($this->_data[0])) . chr(13).chr(10);
		}
      
		foreach ($this->_data as $dataKey => $value) {
            foreach ($value as $key => $val) {
                $value[$key] = str_replace(chr(13).chr(10), chr(10), $val);
            }
			if ($this->_useHeader) {
				if ($dataKey != 0){
					$rowData = array();
					foreach (array_keys($this->_data[0]) as $key) {
						$rowData[] = (isset($value[$key])) ? '"' . str_replace('"', '""', $value[$key]) . '"' : '""';
					}
					$content .= join($this->_separator, $rowData) . chr(13).chr(10);
				}
			} else {
				$content .= join($this->_separator, $value) . chr(13).chr(10);
			}
		}

		
		switch ($action) {
			case "FILE":

				touch($parameter);
				$handle = fopen($parameter, "w");
				fwrite($handle, mb_convert_encoding($content, "ISO-8859-2", CHARSET));
				fclose($handle);

				break;

			case "DOWNLOAD":

				if (is_null($parameter)) {
					$parameter = "export-" . date("Ymd") . ".csv";
				}

				$content = mb_convert_encoding($content, "ISO-8859-2", CHARSET);

				header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
				header("Content-Type: application/force-download");
				header("Content-Type: application/octet-stream");
				header("Content-Type: application/download");
				header('Content-Disposition: attachment; filename="' . $parameter . '"');
				header("Content-Length: " . strlen($content));
				header("Pragma: public");
				header("Expires: 0");
				echo $content;
				die;

				break;

			default:
				return $content;
				break;
		}
	}

}

?>